home *** CD-ROM | disk | FTP | other *** search
- /*
- TranslateLinefeeds.c helps to resolve an incompatibility between the MPW stdio
- library and code resources generated by the THINK C compiler. This is a problem
- if you need to link them together. The problem is that MPW and THINK C have
- adopted different solutions to the problem that Standard C specifies that
- linefeeds should be represented as '\n' (normally 10) inside programs, yet
- Apple, in their wisdom, decided that linefeeds should be represented by 13
- (normally '\r') in Macintosh ASCII text files. The problem is handled invisibly
- by both compilers. MPW redefines '\n' to mean 13. THINK C translates 13 to 10
- (and vice versa) when writing and reading text streams. Unfortunately, when you
- compile THINK C code resources that call the MPW stdio library both solutions
- are eliminated and the old problem raises its ugly head.
-
- This file does NOT SUPPORT Metrowerks CodeWarrior C compiler.
-
- TranslateLinefeeds.c intercepts the calls to the (MPW) stdio library and partially
- implements the THINK C stdio library convention of translating \n to \r and vice
- versa on input and output to text files. Let's call this "linefeed translation".
- (As in the THINK C stdio library, no translation is performed for binary files.)
- These routines should only be used by THINK C code resources that must use the
- MPW stdio library (because the MPW C stdio library doesn't do linefeed
- translation). Don't change your C programs; use the standard names for the stdio
- library routines and just #include the TranslateLinefeeds.h header (after stdio.h).
- The TranslateLinefeeds.h header uses preprocessor macros to redirect nearly all the
- stdio calls to this file, which interposes linefeed translation and calls the
- (MPW) stdio library.
-
- I've implemented all the i/o routines in stdio.h except fscanf and scanf.
- They're difficult to handle, and I suspect that most uses of those routines
- wouldn't distinguish /n from /r anyway.
-
- All the printf-related routines are funneled through vfprintfTL. The actual
- i/o is done by vfprintf(). If it's a "text" stream (as opposed to a "binary"
- stream), then we translate the format string before calling vfprintf(), and
- translate again afterwards, restoring the original string. This is a pretty good
- solution, translating most of the linefeeds, but it fails to translate linefeeds
- that appear in string and char arguments.
-
- Our implementation of translation is incomplete for printf et al., and
- nonexistent for scanf and fscanf because scanning the variable argument list
- would require too much effort, requiring us to implement a large fraction of the
- printf/scanf code: parsing the format string into tokens, retrieving each
- argument, and passing them one at a time to fprintf/scanf.
-
- The time overhead of these routines is negligible. All stdio functions that may
- be implemented as inline macros are redefined by TranslateLinefeeds.h as new inline
- macros that call the original routines.
-
- Note that the getchar and putchar macros in TranslateLinefeeds.h assume that stdin
- and stdout are "text" streams, though I haven't checked whether this is
- guaranteed by Standard C.
-
- For debugging, disabling the TRANSLATE flag results in the identity translation,
- making all the code innocuous.
-
- HISTORY:
- 7/31/93 dgp wrote it.
- 7/31/93 dgp Added support for MPW stdio library.
- 9/20/93 dgp Rewrote vfprintfTL to work with text strings of unlimited length.
- Documented limitation of the new vfprintfTL. Implemented
- getc, putc, getchar, and putchar as inline macros, in TranslateLinefeeds.h.
- */
- #if !defined(THINK_C)
- #error "This file is intended solely for THINK C resources that will be called by MPW"
- #else
- #include "TranslateLinefeeds.h"
- #include <string.h>
- #undef fread
- #undef fwrite
- #undef fgetc
- #undef ungetc
- #undef fputc
- #undef gets
- #undef fgets
- #undef fputs
- #undef vfprintf
- #define TRANSLATE 1 /* set this to zero for identity translation, for debugging */
-
- unsigned char translateLinefeed[256]={
- #if TRANSLATE
- 0,1,2,3,4,5,6,7,8,9,13,11,12,10,14,15,16,17,18,19
- #else
- 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19
- #endif
- ,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39
- ,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59
- ,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79
- ,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99
- ,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119
- ,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139
- ,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159
- ,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179
- ,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199
- ,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219
- ,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239
- ,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
- };
-
- void TranslateLinefeeds(register char *s,register size_t n)
- {
- if(s!=NULL)for(;n>0;n--)*s++=translateLinefeed[(unsigned char)*s];
- }
-
- size_t freadTL(void *s,size_t size,size_t numitems,FILE *stream)
- {
- numitems=fread(s,size,numitems,stream);
- if(IS_TEXT(stream))TranslateLinefeeds(s,size*numitems);
- return numitems;
- }
- size_t fwriteTL(void *s,size_t size,size_t numitems,FILE *stream)
- {
- size_t n;
-
- if(IS_TEXT(stream))TranslateLinefeeds(s,size*numitems);
- n=fwrite(s,size,numitems,stream);
- if(IS_TEXT(stream))TranslateLinefeeds(s,size*numitems);
- return n;
- }
- int fgetcTL(FILE *stream)
- {
- char c;
-
- c=fgetc(stream);
- if(IS_TEXT(stream))return translateLinefeed[(unsigned char)c];
- else return c;
- }
- char *fgetsTL(char *string,int n,FILE *stream)
- {
- char *s;
-
- s=fgets(string,n,stream);
- if(IS_TEXT(stream))TranslateLinefeeds(s,strlen(s));
- return s;
- }
- int fputcTL(int c,FILE *stream)
- {
- int i;
-
- if(IS_TEXT(stream))c=translateLinefeed[(unsigned char)c];
- return fputc(c,stream);
- }
- int fputsTL(char *s,FILE *stream)
- {
- int error;
-
- if(IS_TEXT(stream))TranslateLinefeeds(s,strlen(s));
- error=fputs(s,stream);
- if(IS_TEXT(stream))TranslateLinefeeds(s,strlen(s));
- return error;
- }
- int fprintfTL(FILE *stream,const char *format,...)
- {
- va_list args;
- int n;
-
- va_start(args,format);
- n=vfprintfTL(stream,format,args);
- va_end(args);
- return n;
- }
- char *getsTL(char *string)
- {
- char *s;
-
- s=gets(string);
- if(IS_TEXT(stdin))TranslateLinefeeds(s,strlen(s));
- return s;
- }
- int printfTL(char *format,...)
- {
- va_list args;
- int n;
-
- va_start(args,format);
- n=vfprintfTL(stdout,format,args);
- va_end(args);
- return n;
- }
- /*
- In vfprintfTL we only translate the format string. We'll miss linefeeds that
- are hiding in char and string arguments in the variable argument list. Finding
- those would require a much more elaborate program, which would parse the format
- string.
- */
- int vfprintfTL(FILE *stream,const char *format,va_list args)
- {
- int n;
-
- if(IS_TEXT(stream))TranslateLinefeeds((char *)format,strlen((char *)format));
- n=vfprintf(stream,format,args);
- if(IS_TEXT(stream))TranslateLinefeeds((char *)format,strlen((char *)format));
- return n;
- }
- int vprintfTL(char *format,va_list args)
- {
- return vfprintfTL(stdout,format,args);
- }
- #endif